﻿using System.Collections.ObjectModel;
using System.Net.Sockets;
using System.Windows;
using System.Windows.Input;
using Chess.Client.Model;
using Chess.Client.View;
using Chess.Common;
using MvvmToolkit.Commands;
using MvvmToolkit.ViewModels;

namespace Chess.Client.ViewModel
{
    using System.Windows.Threading;

    internal class MainViewModel : ViewModelBase
    {
        public MainViewModel(Dispatcher dispatcher)
        {
            _clientService = new ClientService(dispatcher);
            _clientService.Update += OnUpdate;
            _profile = new ProfileViewModel(_clientService, new ProfileModel());
            Clients = new ObservableCollection<ClientViewModel>();
            ChessBoard = new ChessBoardViewModel(ClientService);
            _logService = new LogService();
            CanMove = true;
        }

        private LogService _logService;
        private ClientService _clientService;

        public bool CanMove { get; set; }

        public ChessBoardViewModel ChessBoard { get; set; }

        public ClientService ClientService { get { return _clientService; } }

        private ProfileViewModel _profile;
        public ProfileViewModel Profile
        {
            get { return _profile; }
            set
            {
                _profile = value;
                OnPropertyChanged("Profile");
            }
        }

        private string _antagonistName;
        public string AntagonistName
        {
            get { return _antagonistName; }
            set
            {
                _antagonistName = value;
                OnPropertyChanged("AntagonistName");
            }
        }

        public ObservableCollection<ClientViewModel> Clients { get; set; }

        private DelegateCommand _profileCommand;
        private DelegateCommand<ClientViewModel> _suggestGameCommand;

        public ICommand ProfileCommand
        {
            get { return _profileCommand ?? (_profileCommand = new DelegateCommand(ProfileButtonClick)); }
        }

        public ICommand SuggestGameCommand
        {
            get { return _suggestGameCommand ?? (_suggestGameCommand = new DelegateCommand<ClientViewModel>(SuggestGame)); }
        }

        private async void SuggestGame(ClientViewModel client)
        {
            if (client != null)
            {
                var answer = await _clientService.SuggestGame(client.Name);
                string message = "";
                switch (answer.Answer)
                {
                    case SuggestGameAnswerType.Ok:
                        AntagonistName = answer.UserName;
                        CanMove = true;
                        message = string.Format("Suggestion the game was accepted by '{0}' user.", answer.UserName);
                        break;
                    case SuggestGameAnswerType.No:
                        message = string.Format("Suggestion the game was rejected by '{0}' user.", answer.UserName);
                        break;
                }
                MessageBox.Show(message, "Message", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        private void OnUpdate(PackageType packagetype, object[] args)
        {
            var package = args[0];
            switch (packagetype)
            {
                case PackageType.ClientsList:
                    {
                        Clients.Clear();
                        var clientsListPackage = package as ClientsListPackage;
                        var connectedClients = clientsListPackage.ConnectedClients;
                        foreach(var item in connectedClients)
                        {
                            if (item.ClientName == Profile.Login) continue;
                            var client = new ClientModel();
                            client.Id = 0;
                            client.IpAddress = item.RemoteEp.Address.ToString();
                            client.Name = item.ClientName;
                            client.Port = item.RemoteEp.Port;
                            client.Loggined = item.Loggined;
                            Clients.Add(new ClientViewModel(client));
                        }
                    }
                    break;
                case PackageType.SuggestGame:
                    {
                        ChessBoard.Engine.InitiateBoard();
                        var suggestGamePackage = package as SuggestGamePackage;
                        AntagonistName = suggestGamePackage.UserName;
                        CanMove = false;
                    }
                    break;
                case PackageType.SuggestGameAnswer:
                    CanMove = true;
                    ChessBoard.Engine.InitiateBoard();
                    break;
                case PackageType.ChessMove:
                    {
                        var engine = ChessBoard.Engine;
                        var chessMovePackage = package as ChessMovePackage;
                        engine.MovePiece(chessMovePackage.From.X, chessMovePackage.From.Y, chessMovePackage.To.X, chessMovePackage.To.Y);
                        CanMove = true;
                    }
                    break;
            }
        }

        public void ProfileButtonClick()
        {
            try
            {
                var profileWindow = new ProfileWindow();
                profileWindow.DataContext = _profile;
                profileWindow.ShowDialog();
            }
            catch(SocketException e)
            {
                MessageBox.Show(string.Format("Server not found. {0}", e.Message), "Information", MessageBoxButton.OK);
            }
        }
    }
}
